package handler

import (
	"context"
	"crypto/sha512"
	"fmt"
	"github.com/anaskhan96/go-password-encoder"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"gorm.io/gorm"
	"sale_system/user_srv/global"
	"sale_system/user_srv/model"
	"sale_system/user_srv/proto"
	"strings"
	"time"
)

type UserServer struct {
	proto.UnimplementedUserServer // 一定需要实现这个接口
}

func (s *UserServer) mustEmbedUnimplementedUserServer() {
	//TODO implement me
	panic("implement me")
}

// ModelToResponse 将数据库读取到的user信息转化为用户信息接口的返回
func ModelToResponse(user model.User) proto.UserInfoResponse {

	userInfoRsp := proto.UserInfoResponse{
		Id:       user.ID,
		Phone:    user.Phone,
		Password: user.Password,
		NickName: user.NickName,
		Gender:   user.Gender,
		Role:     int32(user.Role),
	}
	// grpc的message字段有默认值，不能够赋值nil，防止空传递
	if user.Birthday != nil {
		userInfoRsp.Birthday = uint64(user.Birthday.Unix())
	}

	return userInfoRsp
}

// Paginate 分页函数
func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {

		if page <= 0 {
			page = 1
		}
		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 0:
			pageSize = 10
		}
		offset := (page - 1) * pageSize
		return db.Offset(offset).Limit(pageSize)
	}
}

// GetUserList 获取用户列表
func (s *UserServer) GetUserList(ctx context.Context, request *proto.PageInfoRequest) (*proto.UserListResponse, error) {

	zap.S().Infof("获取用户列表")
	var users []model.User
	result := global.DB.Find(&users) // 查找user表，将数据都放进users里

	if result.Error != nil { // 查找失败
		return nil, result.Error
	}

	rsp := &proto.UserListResponse{}
	rsp.Total = int32(result.RowsAffected) // 写入数据个数

	global.DB.Scopes(Paginate(int(request.Pn), int(request.PSize))).Find(&users) // 进行分页查询

	for _, user := range users {

		UserInfo := ModelToResponse(user)
		rsp.Data = append(rsp.Data, &UserInfo)
	}

	return rsp, nil
}

// GerUserByPhone 通过手机号码查询用户
func (s *UserServer) GerUserByPhone(ctx context.Context, request *proto.PhoneRequest) (*proto.UserInfoResponse, error) {

	var user model.User
	result := global.DB.Where(&model.User{Phone: request.Phone}).First(&user)
	if result.RowsAffected == 0 { // 查到0行数据
		fmt.Printf("用户不存在，查询不到phone=%s\n", request.Phone)
		return nil, status.Errorf(codes.NotFound, "用户不存在，查询不到phone=%s", request.Phone)
	}
	if result.Error != nil { // 调用接口错误
		fmt.Println("调用接口错误", result.Error)
		return nil, result.Error
	}

	UserInfo := ModelToResponse(user)
	return &UserInfo, nil
}

// GerUserById 通过ID查询用户
func (s *UserServer) GerUserById(ctx context.Context, request *proto.IdRequest) (*proto.UserInfoResponse, error) {
	var user model.User
	result := global.DB.First(&user, request.Id) // 直接查询有误id
	if result.RowsAffected == 0 {                // 查到0行数据
		return nil, status.Errorf(codes.NotFound, "用户不存在，查询不到ID=%d", request.Id)
	}
	if result.Error != nil { // 调用接口错误
		return nil, result.Error
	}

	UserInfo := ModelToResponse(user)
	return &UserInfo, nil
}

// CreateUser 注册新用户
func (s *UserServer) CreateUser(ctx context.Context, request *proto.CreateUserRequest) (*proto.UserInfoResponse, error) {

	var user model.User
	result := global.DB.Where(&model.User{Phone: request.Phone}).First(&user)
	fmt.Println(user)
	if result.RowsAffected == 1 { // 说明用户存在
		return nil, status.Errorf(codes.AlreadyExists, "用户[%s]已存在，不可重复添加", request.Phone)
	}

	// 用户不存在，开始创建用户
	user.Phone = request.Phone
	user.NickName = request.NickName

	// 密码加盐进行哈希
	options := &password.Options{SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New}
	salt, encodePassword := password.Encode(request.Password, options)

	user.Password = fmt.Sprintf("$pbkdf2-sha512$%s$%s", salt, encodePassword)

	result = global.DB.Create(&user)
	if result.Error != nil { // 创建失败
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	userInfoRsp := ModelToResponse(user)

	return &userInfoRsp, nil
}

// UpdateUser 更新用户信息
func (s *UserServer) UpdateUser(ctx context.Context, request *proto.UpdateUserRequest) (*emptypb.Empty, error) {
	// 先查用户存不存在
	var user model.User
	result := global.DB.First(&user, request.Id)
	if result.RowsAffected == 0 { // 说明用户不存在
		return nil, status.Errorf(codes.NotFound, "用户[%d]不存在，不可进行修改", request.Id)
	}
	user.NickName = request.NickName

	birthday := time.Unix(int64(request.Birthday), 0)
	user.Birthday = &birthday
	user.Gender = request.Gender

	// 为什么不修改role？

	// 进行更新
	result = global.DB.Save(&user)
	if result.Error != nil { // 数据库内部调用错误
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &emptypb.Empty{}, nil // 更新不需要返回值
}

// VerifyPassword 验证密码
func (s *UserServer) VerifyPassword(ctx context.Context, request *proto.VerifyRequest) (*proto.VerifyResponse, error) {

	options := &password.Options{SaltLen: 16, Iterations: 100, KeyLen: 32, HashFunction: sha512.New}
	// 验证是否正确
	storagePwdSlice := strings.Split(request.EncryptedPassword, "$")
	verify := password.Verify(request.Password, storagePwdSlice[2], storagePwdSlice[3], options)

	return &proto.VerifyResponse{Success: verify}, nil
}
